// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:collection';
import 'dart:math' as math;
import 'sequential_animation.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class AnimatedListSample extends StatefulWidget {
  @override
  _AnimatedListSampleState createState() => _AnimatedListSampleState();
}

class _AnimatedListSampleState extends State<AnimatedListSample> {
  final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
  ListModel<int> _list;
  int _selectedItem;
  int _nextItem; // The next item inserted when the user presses the '+' button.

  @override
  void initState() {
    super.initState();
    _list = ListModel<int>(
      listKey: _listKey,
      initialItems: <int>[0, 1, 2],
      removedItemBuilder: _buildRemovedItem,
    );
    _nextItem = 3;
  }

  // Used to build list items that haven't been removed.
  Widget _buildItem(
      BuildContext context, int index, Animation<double> animation) {
    return CardItem(
      animation: animation,
      item: _list[index],
      selected: _selectedItem == _list[index],
      onTap: () {
        setState(() {
          _selectedItem = _selectedItem == _list[index] ? null : _list[index];
        });
      },
    );
  }

  // Used to build an item after it has been removed from the list. This method is
  // needed because a removed item remains  visible until its animation has
  // completed (even though it's gone as far this ListModel is concerned).
  // The widget will be used by the [AnimatedListState.removeItem] method's
  // [AnimatedListRemovedItemBuilder] parameter.
  Widget _buildRemovedItem(
      int item, BuildContext context, Animation<double> animation) {
    return CardItem(
      animation: animation,
      item: item,
      selected: false,
      // No gesture detector here: we don't want removed items to be interactive.
    );
  }

  // Insert the "next item" into the list model.
  void _insert() {
    final int index =
        _selectedItem == null ? _list.length : _list.indexOf(_selectedItem);
    _list.insert(index, _nextItem++);
  }

  // Remove the selected item from the list model.
  void _remove() {
    if (_selectedItem != null) {
      _list.removeAt(_list.indexOf(_selectedItem));
      setState(() {
        _selectedItem = null;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('AnimatedList'),
          actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.add_circle),
              onPressed: _insert,
              tooltip: 'insert a new item',
            ),
            IconButton(
              icon: const Icon(Icons.remove_circle),
              onPressed: _remove,
              tooltip: 'remove the selected item',
            ),
          ],
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: AnimatedList(
            key: _listKey,
            initialItemCount: _list.length,
            itemBuilder: _buildItem,
          ),
        ),
      ),
    );
  }
}

/// Keeps a Dart List in sync with an AnimatedList.
///
/// The [insert] and [removeAt] methods apply to both the internal list and the
/// animated list that belongs to [listKey].
///
/// This class only exposes as much of the Dart List API as is needed by the
/// sample app. More list methods are easily added, however methods that mutate the
/// list must make the same changes to the animated list in terms of
/// [AnimatedListState.insertItem] and [AnimatedList.removeItem].
class ListModel<E> {
  ListModel({
    @required this.listKey,
    @required this.removedItemBuilder,
    Iterable<E> initialItems,
  })  : assert(listKey != null),
        assert(removedItemBuilder != null),
        _items = List<E>.from(initialItems ?? <E>[]);

  final GlobalKey<AnimatedListState> listKey;
  final dynamic removedItemBuilder;
  final List<E> _items;

  AnimatedListState get _animatedList => listKey.currentState;

  void insert(int index, E item) {
    _items.insert(index, item);
    _animatedList.insertItem(index);
  }

  E removeAt(int index) {
    final E removedItem = _items.removeAt(index);
    if (removedItem != null) {
      _animatedList.removeItem(index,
          (BuildContext context, Animation<double> animation) {
        return removedItemBuilder(removedItem, context, animation);
      });
    }
    return removedItem;
  }

  int get length => _items.length;

  E operator [](int index) => _items[index];

  int indexOf(E item) => _items.indexOf(item);
}

class _AlwaysCompleteAnimation extends Animation<double> {
  const _AlwaysCompleteAnimation();

  @override
  void addListener(VoidCallback listener) {}

  @override
  void removeListener(VoidCallback listener) {}

  @override
  void addStatusListener(AnimationStatusListener listener) {}

  @override
  void removeStatusListener(AnimationStatusListener listener) {}

  @override
  AnimationStatus get status => AnimationStatus.completed;

  @override
  double get value => 1.0;

  @override
  String toString() => 'kAlwaysCompleteAnimation';
}

/// Displays its integer item as 'item N' on a Card whose color is based on
/// the item's value. The text is displayed in bright green if selected is true.
/// This widget's height is based on the animation parameter, it varies
/// from 0 to 128 as the animation varies from 0.0 to 1.0.
class CardItem extends StatelessWidget {
  const CardItem(
      {Key key,
      Animation<double> animation,
      this.onTap,
      @required this.item,
      this.selected: false})
      :
        assert(animation != null),
        assert(item != null && item >= 0),
        assert(selected != null),
        this.animation = animation ?? const _AlwaysCompleteAnimation(),
        super(key: key);

  final Animation<double> animation;
  final VoidCallback onTap;
  final int item;
  final bool selected;

  @override
  Widget build(BuildContext context) {
    TextStyle textStyle = Theme.of(context).textTheme.display1;
    if (selected)
      textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
    return Padding(
      padding: const EdgeInsets.all(10.0),
      child: SizeTransition(
        axis: Axis.vertical,
        sizeFactor: animation,
        child: GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTap: onTap,
          child: SizedBox(
            height: 128.0,
            child: Card(
              color: Colors.primaries[item % Colors.primaries.length],
              child: Center(
                child: Text('Item $item', style: textStyle),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _Item {
  String _name;
  int _age;

  _Item(this._name, this._age);

  @override
  String toString() {
    return '_Item{_name: $_name, _age: $_age}';
  }
}

void main() {
  int time = 0;

  var hashMap = HashMap();
  var item1 = _Item("able", 20);
  hashMap["hello"] = item1;
  var hashMap2 = HashMap.from(hashMap);
  hashMap2['hello']._name = "able2";

  var hashMap22 = hashMap2['hello'];
  print(
      "hashMap:${hashMap22.toString()} and ${hashMap22.hashCode} item:${item1.toString()} and ${item1.hashCode}");

  var valueNotifier = ValueNotifier(time);
  Timer.periodic(const Duration(hours: 1), (timer) {
    print("time:$time");
    time++;
    valueNotifier.value = time;
  });

  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: const Text(
          "animatedList",
        ),
      ),
//      body: MyAnimatedWidget(listenable: valueNotifier),
      body: StaggerAnimation(),
    ),
  ));
}

class _ClipRect extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: <Widget>[
        Image.asset("images/birds_by_pond.jpg"),
//        ClipRect(
//          child:
        Align(
          alignment: Alignment.bottomCenter,
          heightFactor: 0.5,
          child: Image.asset("images/birds_by_pond.jpg"),
        ),
//        ),
        Image.asset("images/birds_by_pond.jpg"),
      ],
    );
  }
}

class _SizeTransitionView extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _SizeTransitionState();
  }
}

/// 使用`SizeTransition`实现区域折叠的功能
class _SizeTransitionState extends State<_SizeTransitionView>
    with SingleTickerProviderStateMixin {
  bool _expanded = false;
  AnimationController _controller;

  @override
  void initState() {
    _controller = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 100));

    super.initState();
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        RaisedButton(
          onPressed: () {
            _expanded = !_expanded;
            setState(() {});
            switch (_controller?.status) {
              case AnimationStatus.completed:
                _controller?.reverse();
                break;
              case AnimationStatus.dismissed:
                _controller?.forward();
                break;
              default:
                break;
            }
          },
          child: Text(_expanded ? "折叠" : "展开"),
        ),
        SizeTransition(
            sizeFactor: _controller,
            child: Container(
              color: Colors.blue,
              child: Column(
                children: <Widget>[
                  Text("First Line-----------------"),
                  Text("Second Line-----------------"),
                  Text("Third Line-----------------"),
                  Text("Fourth Line-----------------"),
                  Text("Fifth Line-----------------"),
                  Text("Sixth Line-----------------"),
                ],
              ),
            ))
      ],
    );
  }
}

class _ScaleAndRotateViewWrapper extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ScaleAndRotateWrapperState();
  }
}

class _ScaleAndRotateWrapperState extends State<_ScaleAndRotateViewWrapper>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 2));
    super.initState();
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.blueGrey,
        width: MediaQuery.of(context).size.width,
        child: Column(
          children: <Widget>[
            RaisedButton(
              onPressed: () {
                switch (_controller?.status) {
                  case AnimationStatus.completed:
                    _controller?.reverse();
                    break;
                  case AnimationStatus.dismissed:
                    _controller?.forward();
                    break;
                  default:
                    break;
                }
              },
              child: Text("开始动画"),
            ),
            _ScaleAndRotateView(_controller)
          ],
        ));
  }
}

class _ScaleAndRotateView extends AnimatedWidget {
  final AnimationController _controller;
  final FadeTransition _fadeTransition;

  _ScaleAndRotateView(this._controller)
      : this._fadeTransition = FadeTransition(
          opacity: _controller,
          child: Image.asset(
            "images/birds_by_pond.jpg",
            width: 157,
            height: 200,
          ),
        ),
        super(listenable: _controller);

  @override
  Widget build(BuildContext context) {
    var value = _controller.value;
    var matrix4 = Matrix4.identity();
    var scale = value > 0 ? value : -value;
    var item = FadeTransition(
      opacity: _controller,
      child: Image.asset(
        "images/birds_by_pond.jpg",
        width: 157,
        height: 200,
      ),
    );
    print(
        "scale:$scale rotate:${scale * math.pi * 2.0} --->_fadeTransition:$item}");
//    Vector3 vector3 = Vector3(78.0, 100.0, 0.0);
    matrix4 = matrix4
      ..rotateZ(scale * math.pi * 2.0)
      ..scale(scale, scale, 1.0);
    Offset offset = Offset(78.0, 100.0);

    var finalResult = Matrix4.identity()
      ..translate(offset.dx, offset.dy)
      ..multiply(matrix4)
      ..translate(-offset.dx, -offset.dy);

    return Transform(
      transform: finalResult,
//      alignment: Alignment.center,
//      origin: offset,
      child: item,
    );
  }
}

class _ScaleAndRotateView2 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ScaleAndRotateView2State();
  }
}

class _ScaleAndRotateView2State extends State<_ScaleAndRotateView2>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 2));
    super.initState();
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox.expand(
      child: Column(
        children: <Widget>[
          RaisedButton(
            onPressed: () {
              handleAnimation(_controller);
            },
            child: const Text("开始动画"),
          ),
          ScaleTransition(
            scale: _controller,
            child: RotationTransition(
              turns: _controller,
              child: Image.asset("images/birds_by_pond.jpg"),
            ),
          )
        ],
      ),
    );
  }
}

void handleAnimation(AnimationController controller) {
  switch (controller?.status) {
    case AnimationStatus.dismissed:
      controller?.forward();
      break;
    case AnimationStatus.completed:
      controller?.reverse();
      break;
    default:
      break;
  }
}

class _ScaleView extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ScaleState();
  }
}

class _ScaleState extends State<_ScaleView> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        GestureDetector(
            onTap: () {
              print("click area");
            },
            child: Container(color: Colors.green, child: _generateChild())),
        GestureDetector(
            onTap: () {
              print("click area");
            },
            child: Container(color: Colors.blue, child: _generateChild2()))
      ],
    );
  }

  Widget _generateChild2() {
    return ClipRect(
        child: Align(
      alignment: Alignment.bottomCenter,
      widthFactor: 0.5,
      heightFactor: 0.5,
      child: Image.asset("images/birds_by_pond.jpg"),
    ));
  }

  Widget _generateChild() {
    return Transform(
      transform: Matrix4.identity()..scale(0.5, 0.5),
      child: Image.asset("images/birds_by_pond.jpg"),
    );
  }
}

/// 对于Align，如果不用ClipRect包裹的话，则缩小是无效的，如果用ClipRect包裹，则控件本身也变小
/// ScaleTransition缩小只是视图的缩小，而控件本身的大小并没有改变
